package org.example.exam.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.example.exam.entity.Category;
import org.example.exam.entity.Question;
import org.example.exam.mapper.CategoryMapper;
import org.example.exam.mapper.QuestionMapper;
import org.example.exam.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Autowired
    private QuestionMapper questionMapper;

    /**
     * 查询分类列表同时查询分类的题目数量
     * @return
     */
    @Override
    public List<Category> findCategoryList() {
        // 1、查询所有分类信息集合 根据排序（正序）进行查询
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(Category::getSort); // sort正序排序查询
        List<Category> categoryList = this.list(queryWrapper); // 里面的数据少了count

        // 2、在QuestionMapper中定义一个查询方法，category_id进行分组，并统计每个分类下的count
        // [map {<category_id, 14>, <count, 1>} , {<category_id, 14>, <count, 1>}]
        List<Map<String, Long>> maps = questionMapper.selectCategoryQuestionCount();

        // 将maps这个集合装成一个大Map,键 --> category_id 对应的值，值 --> count对应的值
        Map<Long, Long> collect = maps.stream().collect(Collectors.toMap(
                map -> map.get("category_id"), // 取 category_id对应的值作为键
                map -> map.get("count") // 取 count 对应的值作为值
        ));

        // 3、题目查询的分类的题目数量赋值给分类集合
        for (Category category : categoryList) {
            Long id = category.getId();
            category.setCount(collect.getOrDefault(id, 0L));
        }

        // 返回对应的结果
        return categoryList;
    }

    @Override
    public List<Category> findCategoryTreeList() {
        // 拿到每个分类和每个分类对应的数量
        List<Category> categoryList = this.findCategoryList();


        // 4、将分类信息进行分组（parent_id）
        // < key:parent_id, value:list<子分类> >
        Map<Long, List<Category>> map = categoryList.stream()
                .collect(Collectors.groupingBy(Category::getParentId));

        // 5、筛选分类信息 筛选出一级分类
        List<Category> parentCategoryList = categoryList.stream()
                .filter(c -> c.getParentId() == 0)
                .collect(Collectors.toList());

        // 6、给一级分类循环，获取子分类并且计算count（父分类的count + 所有子分类的count）
        parentCategoryList.forEach(parent -> {
            // 当前父分类下的子分类
            // 但是有可能父分类下没有子分类，如果没有子分类就放一个空集合
            List<Category> sonCategoryList = map.getOrDefault(parent.getId(), new ArrayList<>());
            // 将子分类集合赋值给父分类
            parent.setChildren(sonCategoryList);

            // 将子分类的所有count相加赋值给父分类
            Long totalCount = sonCategoryList.stream().collect(Collectors.summingLong(Category::getCount));
            parent.setCount(totalCount + parent.getCount());
        });


        return parentCategoryList;
    }


    /**
     * 保存分类信息
     * @param category
     */
    @Override
    public void saveCategory(Category category) {
        // 1、当前父分类下不能存在同名的子分类
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Category::getParentId, category.getParentId());
        queryWrapper.eq(Category::getName, category.getName());
        long count = this.count(queryWrapper);
        if (count > 0) {
            throw new RuntimeException("%s父分类下已经存在名为：%s的子分类信息！本次添加失败".formatted(category.getParentId(), category.getName()));
        }

        // 2、保存当前分类即可
        this.save(category);
    }

    /**
     * 更新分类信息
     * @param category
     */
    @Override
    public void updateCategory(Category category) {
        // 1、校验：同一个父类下不能与其他子分类的name相同 但是可以与自己和自己原来的name相同
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Category::getParentId, category.getParentId());
        queryWrapper.eq(Category::getName, category.getName());
        // 加多一个前提，不能与当前子分类的id相同，如果不同的id有相同的名字，那么就不允许保存
        queryWrapper.ne(Category::getId, category.getId());

        long count = this.count(queryWrapper);

        if (count > 0) {
            throw new RuntimeException("%s父分类下已经存在名为：%s的子分类信息！本次更新失败".formatted(category.getParentId(), category.getName()));
        }
        // 2、更新分类信息
        this.updateById(category);
    }

    @Override
    public void deleteCategory(Long id) {
        // 1、判断是不是一级分类
        Category category = this.getById(id);
        if (category == null) {
            log.debug("在删除之前已经被删除");
            return;
        }

        if (category.getParentId() == 0) {
            // 证明是一级分类，不允许删除
            throw new RuntimeException("id=%s为一级分类，不允许删除".formatted(id));
        }

        // 2、判断有没有关联的题目
        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        questionLambdaQueryWrapper.eq(Question::getCategoryId, id);
        Long count = questionMapper.selectCount(questionLambdaQueryWrapper);
        if (count > 0) {
            throw new RuntimeException("id=%s的分类删除失败！因为下面有关联的题目数量为：%s".formatted(id, count));
        }

        // 3、才可以进行删除分类
        this.removeById(id);
    }
}